using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Collections.Specialized;

namespace Pixysoft.Collections
{
    public class MostRecentlyUsed : DictionaryBase
    {
        uint m_max = 50;
        DoubleLinkedList m_list = new DoubleLinkedList();
        HybridDictionary m_linkToKey = new HybridDictionary(); // LinkItem -> key

        /// <summary>
        /// Default constructor for the most recently used items using the default size (50)
        /// </summary>
        public MostRecentlyUsed()
        {
            //
            // TODO: Add constructor logic here
            //
        }


        /// <summary>
        /// Construct a most recently used items list with the maximum number of items
        /// allowed in the list.
        /// </summary>
        /// <param name="maxItems">Maximum number of items allowed</param>
        public MostRecentlyUsed(uint maxItems)
        {
            m_max = maxItems;
        }

        public object this[object key]
        {
            get
            {

                DoubleLinkedList.LinkItem item = (DoubleLinkedList.LinkItem)Dictionary[key];

                if (item == null)
                    return null;

                m_list.MoveToHead(item);

                return (item.Item);
            }
            set
            {
                DoubleLinkedList.LinkItem link = null;

                if (Dictionary.Contains(key))
                {
                    link = (DoubleLinkedList.LinkItem)Dictionary[key];
                    link.Item = value;

                    m_list.MoveToHead(link);

                    Dictionary[key] = link;

                    // Keep a reverse index from the link to the key
                    m_linkToKey[link] = key;
                }
                else
                {
                    Add(key, value);
                }
            }
        }

        public ICollection Keys
        {
            get
            {
                return (Dictionary.Keys);
            }
        }

        public ICollection Values
        {
            get
            {
                return (Dictionary.Values);
            }
        }

        public void Add(object key, object value)
        {
            DoubleLinkedList.LinkItem link = m_list.Prepend(value);

            Dictionary.Add(key, link);

            // Keep a reverse index from the link to the key
            m_linkToKey[link] = key;

        }

        public bool Contains(object key)
        {
            bool hasKey = Dictionary.Contains(key);

            // Update the reference for this link
            if (hasKey)
                m_list.MoveToHead((DoubleLinkedList.LinkItem)Dictionary[key]);

            return (hasKey);
        }

        public void Remove(object key)
        {
            DoubleLinkedList.LinkItem link =
                (DoubleLinkedList.LinkItem)Dictionary[key];

            Dictionary.Remove(key);

            if (link != null)
            {
                m_list.RemoveLink(link);

                // Keep a reverse index from the link to the key
                m_linkToKey.Remove(link);
            }
        }

        protected override void OnInsert(Object key, Object value)
        {
            while (Dictionary.Keys.Count >= m_max)
            {
                // Purge an item from the cache
                DoubleLinkedList.LinkItem tail = m_list.TailLink;

                if (tail != null)
                {
                    object purgeKey = m_linkToKey[tail];

                    // Fire the event
                    if (OnPurgedFromCache != null && OnPurgedFromCache.GetInvocationList().Length > 0)
                    {
                        OnPurgedFromCache(purgeKey, tail.Item);
                    }

                    Remove(purgeKey);
                }
            }
        }

        protected override void OnRemove(Object key, Object value)
        {
            ;
        }

        protected override void OnSet(Object key, Object oldValue, Object newValue)
        {
            ;
        }

        protected override void OnValidate(Object key, Object value)
        {
            ;
        }

        /// <summary>
        /// The maximum capacity of the list
        /// </summary>
        public uint Capacity
        {
            get { return m_max; }
            set
            {
                if (Capacity < 1)
                    throw new Exception("Negative number!");
                m_max = value;
            }
        }
        public delegate void PurgedFromCacheDelegate(object key, object value);

        /// <summary>
        /// Event that is fired when an item falls outside of the cache
        /// </summary>
        public event PurgedFromCacheDelegate OnPurgedFromCache;

        public override string ToString()
        {
            StringBuilder buff = new StringBuilder(Convert.ToInt32(m_max));

            buff.Append("[");

            foreach (object item in m_list)
            {
                if (buff.Length > 1)
                    buff.Append(", ");

                buff.Append(item.ToString());
            }

            buff.Append("]");

            return buff.ToString();
        }

    }
}
